home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / wnos / wn941101 / telnet.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-10  |  9.8 KB  |  494 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include <time.h>
  4. #ifdef    __TURBOC__
  5. #include <io.h>
  6. #include <fcntl.h>
  7. #endif
  8. #include "global.h"
  9. #include "config.h"
  10. #include "mbuf.h"
  11. #include "socket.h"
  12. #include "telnet.h"
  13. #include "session.h"
  14. #include "proc.h"
  15. #include "tty.h"
  16. #include "commands.h"
  17. #include "netuser.h"
  18.  
  19. static int near filemode __ARGS((FILE *fp,int mode));
  20. static int near gen_telnet __ARGS((char *name, int type, int ipport, int split, int msg, int bbs));
  21.  
  22. static int Refuse_echo = 0;
  23. static int Tn_cr_mode = 0;    /* if true turn <cr> to <cr-nul> */
  24.  
  25. #ifdef    DEBUG
  26. char *T_options[] = {
  27.     "Transmit Binary",
  28.     "Echo",
  29.     "",
  30.     "Suppress Go Ahead",
  31.     "",
  32.     "Status",
  33.     "Timing Mark"
  34. };
  35. #endif
  36.  
  37. #ifdef    MAILBOX
  38. /* Execute user BBS command */
  39. int
  40. dobbs(argc,argv,p)
  41. int argc;
  42. char *argv[];
  43. void *p;
  44. {
  45.     if(Ip_addr == 0) {
  46.         tputs(Noipaddr);
  47.         return -1;
  48.     }
  49.     return gen_telnet("LocBBS",TELNET,IPPORT_TELNET,1,0,1);
  50. }
  51. #endif
  52.  
  53. /* Execute user chat command */
  54. int
  55. dochat(argc,argv,p)
  56. int argc;
  57. char *argv[];
  58. void *p;
  59. {
  60.     strlwr(argv[1]);
  61.     return gen_telnet(argv[1],TELNET,IPPORT_TTYLINK,1,1,0);
  62. }
  63.  
  64. /* Execute user telnet command */
  65. int
  66. dotelnet(argc,argv,p)
  67. int argc;
  68. char *argv[];
  69. void *p;
  70. {
  71.     int split, arg = atoi(argv[2]);
  72.  
  73.     if(argc > 2)
  74.         split =    (arg == IPPORT_TTYLINK || arg == IPPORT_CONVERS) ? 1 : 0;
  75.     strlwr(argv[1]);
  76.     return gen_telnet(argv[1],TELNET,(argc < 3) ? IPPORT_TELNET : arg,split,1,0);
  77. }
  78.  
  79. static int near
  80. gen_telnet(name,type,ipport,split,msg,bbs)
  81. char *name;
  82. int type;
  83. int ipport;
  84. int split;
  85. int msg;
  86. int bbs;
  87. {
  88.     struct session *sp;
  89.     struct sockaddr_in fsocket;
  90.  
  91.     /* Allocate a session descriptor */
  92.     if((sp = newsession(name,type,split,1)) == NULLSESSION) {
  93.         tputs(Nosess);
  94.         return 1;
  95.     }
  96.  
  97.     fsocket.sin_family = AF_INET;
  98.     fsocket.sin_port = ipport;
  99.  
  100.     if(bbs)
  101.         fsocket.sin_addr.s_addr = Ip_addr;
  102.     else {
  103.         if(msg)
  104.             tprintf("Resolving %s... ",sp->name);
  105.         if((fsocket.sin_addr.s_addr = resolve(sp->name)) == 0){
  106.             tprintf(Badhost,sp->name);
  107.             goto quit;
  108.         }
  109.     }
  110.     if((sp->s = socket(AF_INET,SOCK_STREAM,0)) == -1){
  111.         tputs(Nosocket);
  112.         goto quit;
  113.     }
  114.     if(!(tel_connect(sp,(char *)&fsocket,SOCKSIZE)))
  115.         return 0;
  116. quit:
  117.     keywait(NULLCHAR,1);
  118.     freesession(sp);
  119.     return 1;
  120. }
  121.  
  122. /* Generic interactive connect routine, used by Telnet, AX.25, NET/ROM */
  123. int
  124. tel_connect(sp,fsocket,len)
  125. struct session *sp;
  126. char *fsocket;
  127. int len;
  128. {
  129.     struct telnet tn;
  130.  
  131.     memset((char *)&tn,0,sizeof(tn));
  132.  
  133.     tn.eolmode = Tn_cr_mode;
  134.     tn.session = sp;    /* Upward pointer */
  135.     sp->cb.telnet = &tn;    /* Downward pointer */
  136.     sockmode(sp->s,SOCK_ASCII);    /* Default to ascii mode */
  137.  
  138.     tprintf("Trying %s...\n",psocket((struct sockaddr *)fsocket));
  139.     if(connect(sp->s,fsocket,len) == -1){
  140.         tprintf("%s session failed: %s errno %d\n",
  141.             Sestypes[sp->type], sockerr(sp->s),errno);
  142.         return 1;
  143.     }
  144.     tprintf("%s session connected to %s\n",
  145.         Sestypes[sp->type],sp->name);
  146.     log(sp->s,"%4.4s connect",Sestypes[sp->type]);
  147.     tnrecv(&tn);
  148.     return 0;
  149. }
  150.  
  151. /* Telnet input routine, common to both telnet and ttylink */
  152. void
  153. tnrecv(tn)
  154. struct telnet *tn;
  155. {
  156.     char *cp;
  157.     struct session *sp = tn->session;
  158.     int c, s = sp->s;
  159.  
  160.     /* Fork off the transmit process */
  161.     sp->proc1 = newproc("tel_out",1536,tel_output,0,tn,NULL,0);
  162.  
  163.     /* Process input on the connection */
  164.     while((c = recvchar(s)) != -1){
  165.         if(c != IAC){
  166.             /* Ordinary character */
  167. /*    stripping off the high bit disabled - DB3FL
  168.             if(!tn->remote[TN_TRANSMIT_BINARY])
  169.                 c &= 0x7f;
  170. */
  171.  
  172.             tputc((char)c);
  173.             continue;
  174.         }
  175.         /* IAC received, get command sequence */
  176.         c = recvchar(s);
  177.         switch(c){
  178.         case WILL:
  179.             c = recvchar(s);
  180.             willopt(tn,c);
  181.             break;
  182.         case WONT:
  183.             c = recvchar(s);
  184.             wontopt(tn,c);
  185.             break;
  186.         case DO:
  187.             c = recvchar(s);
  188.             doopt(tn,c);
  189.             break;
  190.         case DONT:
  191.             c = recvchar(s);
  192.             dontopt(tn,c);
  193.             break;
  194.         case IAC:    /* Escaped IAC */
  195.             tputc(IAC);
  196.             break;
  197.         }
  198.     }
  199. quit:
  200.     /* A close was received from the remote host.
  201.      * Notify the user, kill the output task and wait for a response
  202.      * from the user before freeing the session.
  203.      */
  204.     sockmode(sp->output,SOCK_ASCII); /* Restore newline translation */
  205.     cp = sockerr(s);
  206.     tprintf("%s session closed: %s at %s",
  207.         Sestypes[sp->type], cp != NULLCHAR ? cp : "EOF",ctime(&currtime));
  208.     killproc(sp->proc1);
  209.     sp->proc1 = NULLPROC;
  210.     close_s(sp->s);
  211.     sp->s = -1;
  212.     keywait(NULLCHAR,1);
  213.     freesession(sp);
  214. }
  215.  
  216. /* User telnet output task, started by user telnet command */
  217. static void
  218. tel_output(unused,tn1,p)
  219. int unused;
  220. void *tn1;
  221. void *p;
  222. {
  223.     int c;
  224.     struct telnet *tn = (struct telnet *)tn1;
  225.     struct session *sp = tn->session;
  226.  
  227.     /* Send whatever's typed on the terminal */
  228.     while((c = recvchar(sp->input)) != EOF){
  229.         usputc(sp->s,(char)c);
  230.  
  231.         if(!tn->remote[TN_ECHO] && sp->record != NULLFILE)
  232.             putc(c,sp->record);
  233.  
  234.         /* By default, output is transparent in remote echo mode.
  235.          * If eolmode is set, turn a cr into cr-null.
  236.          * This can only happen when in remote echo (raw) mode, since
  237.          * the tty driver normally maps \r to \n in cooked mode.
  238.          */
  239.         if(c == '\r' && tn->eolmode)
  240.             usputc(sp->s,'\0');
  241.  
  242.         if(tn->remote[TN_ECHO])
  243.             usflush(sp->s);
  244.     }
  245.     /* Make sure our parent doesn't try to kill us after we exit */
  246.     sp->proc1 = NULLPROC;
  247. }
  248.  
  249. int
  250. doecho(argc,argv,p)
  251. int argc;
  252. char *argv[];
  253. void *p;
  254. {
  255.     if(argc < 2)
  256.         tprintf("Echo %s\n",Refuse_echo ? "refuse" : "accept");
  257.     else {
  258.         switch(tolower(*argv[1])) {
  259.             case 'r':
  260.                 Refuse_echo = 1;
  261.                 break;
  262.             case 'a':
  263.                 Refuse_echo = 0;
  264.                 break;
  265.             default:
  266.                 tputs("Usage: echo <refuse|accept>\n");
  267.                 return -1;
  268.         }
  269.     }
  270.     return 0;
  271. }
  272.  
  273. /* set for unix end of line for remote echo mode telnet */
  274. int
  275. doeol(argc,argv,p)
  276. int argc;
  277. char *argv[];
  278. void *p;
  279. {
  280.     if(argc < 2)
  281.         tprintf("Eol %s\n",Tn_cr_mode ? "null" : "standard");
  282.     else {
  283.         switch(tolower(*argv[1])) {
  284.             case 'n':
  285.                 Tn_cr_mode = 1;
  286.                 break;
  287.             case 's':
  288.                 Tn_cr_mode = 0;
  289.                 break;
  290.             default:
  291.                 tputs("Usage: eol <standard|null>\n");
  292.                 return -1;
  293.         }
  294.     }
  295.     return 0;
  296. }
  297.  
  298. /* The guts of the actual Telnet protocol: negotiating options */
  299. static void
  300. willopt(tn,opt)
  301. struct telnet *tn;
  302. int opt;
  303. {
  304.     int ack;
  305.  
  306. #ifdef    DEBUG
  307.     tprintf("recv: will ");
  308.     if(uchar(opt) <= NOPTIONS)
  309.         tprintf("%s\n",T_options[opt]);
  310.     else
  311.         tprintf("%u\n",opt);
  312. #endif
  313.  
  314.     switch(uchar(opt)){
  315.     case TN_TRANSMIT_BINARY:
  316.     case TN_ECHO:
  317.     case TN_SUPPRESS_GA:
  318.         if(tn->remote[uchar(opt)] == 1)
  319.             return;        /* Already set, ignore to prevent loop */
  320.         if(uchar(opt) == TN_ECHO){
  321.             if(Refuse_echo){
  322.                 /* User doesn't want to accept */
  323.                 ack = DONT;
  324.                 break;
  325.             } else {
  326.                 /* Put tty into raw mode */
  327.                 tn->session->ttystate.edit = 0;
  328.                 tn->session->ttystate.echo = 0;
  329.                 sockmode(tn->session->s,SOCK_BINARY);
  330.                 sockmode(tn->session->input,SOCK_BINARY);
  331.                 sockmode(tn->session->output,SOCK_BINARY);
  332.                 if(tn->session->record != NULLFILE)
  333.                     filemode(tn->session->record,SOCK_BINARY);
  334.  
  335.             }
  336.         }
  337.         tn->remote[uchar(opt)] = 1;
  338.         ack = DO;
  339.         break;
  340.     default:
  341.         ack = DONT;    /* We don't know what he's offering; refuse */
  342.     }
  343.     answer(tn,ack,opt);
  344. }
  345.  
  346. static void
  347. wontopt(tn,opt)
  348. struct telnet *tn;
  349. int opt;
  350. {
  351. #ifdef    DEBUG
  352.     tprintf("recv: wont ");
  353.     if(uchar(opt) <= NOPTIONS)
  354.         tprintf("%s\n",T_options[uchar(opt)]);
  355.     else
  356.         tprintf("%u\n",uchar(opt));
  357. #endif
  358.     if(uchar(opt) <= NOPTIONS){
  359.         if(tn->remote[uchar(opt)] == 0)
  360.             return;        /* Already clear, ignore to prevent loop */
  361.         tn->remote[uchar(opt)] = 0;
  362.         if(uchar(opt) == TN_ECHO){
  363.             /* Put tty into cooked mode */
  364.             tn->session->ttystate.edit = 1;
  365.             tn->session->ttystate.echo = 1;
  366.             sockmode(tn->session->s,SOCK_ASCII);
  367.             sockmode(tn->session->input,SOCK_ASCII);
  368.             sockmode(tn->session->output,SOCK_ASCII);
  369.             if(tn->session->record != NULLFILE)
  370.                 filemode(tn->session->record,SOCK_ASCII);
  371.         }
  372.     }
  373.     answer(tn,DONT,opt);    /* Must always accept */
  374. }
  375.  
  376. static void
  377. doopt(tn,opt)
  378. struct telnet *tn;
  379. int opt;
  380. {
  381.     int ack;
  382.  
  383. #ifdef    DEBUG
  384.     tprintf("recv: do ");
  385.     if(uchar(opt) <= NOPTIONS)
  386.         tprintf("%s\n",T_options[uchar(opt)]);
  387.     else
  388.         tprintf("%u\n",uchar(opt));
  389. #endif
  390.     switch(uchar(opt)){
  391.     case TN_SUPPRESS_GA:
  392.         if(tn->local[uchar(opt)] == 1)
  393.             return;        /* Already set, ignore to prevent loop */
  394.         tn->local[uchar(opt)] = 1;
  395.         ack = WILL;
  396.         break;
  397.     default:
  398.         ack = WONT;    /* Don't know what it is */
  399.     }
  400.     answer(tn,ack,opt);
  401. }
  402.  
  403. static void
  404. dontopt(tn,opt)
  405. struct telnet *tn;
  406. int opt;
  407. {
  408. #ifdef    DEBUG
  409.     tprintf("recv: dont ");
  410.     if(uchar(opt) <= NOPTIONS)
  411.         tprintf("%s\n",T_options[uchar(opt)]);
  412.     else
  413.         tprintf("%u\n",uchar(opt));
  414. #endif
  415.     if(uchar(opt) <= NOPTIONS){
  416.         if(tn->local[uchar(opt)] == 0){
  417.             /* Already clear, ignore to prevent loop */
  418.             return;
  419.         }
  420.         tn->local[uchar(opt)] = 0;
  421.     }
  422.     answer(tn,WONT,opt);
  423. }
  424.  
  425. static void
  426. answer(tn,r1,r2)
  427. struct telnet *tn;
  428. int r1,r2;
  429. {
  430.     char s[3];
  431.  
  432. #ifdef    DEBUG
  433.     switch(r1){
  434.     case WILL:
  435.         tprintf("sent: will ");
  436.         break;
  437.     case WONT:
  438.         tprintf("sent: wont ");
  439.         break;
  440.     case DO:
  441.         tprintf("sent: do ");
  442.         break;
  443.     case DONT:
  444.         tprintf("sent: dont ");
  445.         break;
  446.     }
  447.     if(r2 <= 6)
  448.         tprintf("%s\n",T_options[r2]);
  449.     else
  450.         tprintf("%u\n",r2);
  451. #endif
  452.  
  453.     s[0] = IAC;
  454.     s[1] = r1;
  455.     s[2] = r2;
  456.     send(tn->session->s,s,3,0);
  457. }
  458.  
  459. #ifdef    __TURBOC__
  460. /* Set end-of-line translation mode on file */
  461. static int near
  462. filemode(fp,mode)
  463. FILE *fp;
  464. int mode;
  465. {
  466.     int omode;
  467.  
  468.     if(fp == NULLFILE)
  469.         return -1;
  470.  
  471.     omode = (fp->flags & _F_BIN) ? SOCK_BINARY : SOCK_ASCII;
  472.  
  473.     switch(mode){
  474.     case SOCK_BINARY:
  475.         fp->flags = _F_BIN;
  476.         setmode(fileno(fp),O_BINARY);
  477.         break;
  478.     case SOCK_ASCII:
  479.         fp->flags &= ~_F_BIN;
  480.         setmode(fileno(fp),O_TEXT);
  481.         break;
  482.     }
  483.     return omode;
  484. }
  485. #else
  486. static int near
  487. filemode(fp,mode)
  488. FILE *fp;
  489. int mode;
  490. {
  491.     return 0;
  492. }
  493. #endif
  494.